package Controller;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Timer;
import java.util.TreeMap;

import model.CustomPoint;
import model.Element;
import model.GameInfo;
import model.Movie;
import model.MovieEvent;
import model.Result;
import model.UrlFile;
import model.CustomPoint.SizeF;
import model.EventProperties.ClickEventProperties;
import model.EventProperties.MoveablePictureEventProperties;
import model.ResultProperties.ChangeGlobleElementTextResultProprties;
import model.ResultProperties.KillEventResultProperties;
import model.ResultProperties.MoveToMovieResultProperties;
import model.ResultProperties.PlaySoundProperties;
import model.ResultProperties.SetFlagResultProperties;
import model.ResultProperties.ShowPictureResultProperties;
import model.ResultProperties.StartActivityProperties;
import model.ResultProperties.StopSoundResultProperties;
import Controller.TimerTasks.EndEventTimerTask;
import Controller.TimerTasks.ParamTimerTask;
import Controller.TimerTasks.StartEventTimerTask;
import Enums.EventType;
import Enums.ResultAction;
import Enums.UiElement;
import Servises.FilesManager;
import Servises.RealSaxParser;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.intouchtv.ari.NabDemoView;


public class GameController {
	private static final int dontReleaseThershold = 3;
	private NabDemoView view;
	private GameInfo gameInfo;
	private Movie currentMovie;
	private SurfaceView viewForCallback;
	private Movie movieForCallback;
	private EventManager eventManager;
	private Timer timer;
	private Movie movieToRelease;
	private boolean switichingMovies;
	boolean EMULATOR_MODE = true;
	public HashMap<String, String> mediaUrlToByteArray;
	private HashMap<String, Integer> audioUrlToSoundPoolId;
	private HashMap<String, String> audioUrlToLocalPath;
	private Handler uiHandler;
	private SoundPool soundPool;
	HashMap<String, MediaPlayer> audioPlayers;

	private HashMap<String, Integer> rawResourceNameToInt;

	public GameController(NabDemoView view, Handler uiHandler) {
		super();
		this.view = view;
		this.gameInfo = null;
		SensorManager sm = null;
		if (!EMULATOR_MODE)
			sm = (SensorManager) view.getSystemService(Context.SENSOR_SERVICE);

		mediaUrlToByteArray = new HashMap<String, String>();
		audioUrlToSoundPoolId = new HashMap<String, Integer>();
		audioUrlToLocalPath = new HashMap<String, String>();

		//soundPool = new SoundPool(4, AudioManager.STREAM_NOTIFICATION, 0);

		audioPlayers = new HashMap<String, MediaPlayer>();  

		this.eventManager = new EventManager(this, sm);

		this.uiHandler = uiHandler;
		
		//rawResourceNameToInt = new HashMap<String, Integer>();
		//rawResourceNameToInt.put("chime", R.raw.chime);
		//rawResourceNameToInt.put("start", R.raw.start);
		//rawResourceNameToInt.put("correct", R.raw.correct);
	}

	public NabDemoView getView() {
		return view;
	}

	public void setView(NabDemoView view) {
		this.view = view;
	}

	public String getDownlodedObject(String url) {
		return mediaUrlToByteArray.get(url);
	}

	public boolean isSwitichingMovies() {
		return switichingMovies;
	}

	public void setSwitichingMovies(boolean switichingMovies) {
		this.switichingMovies = switichingMovies;
	}

	public EventManager getEventManager() {
		return eventManager;
	}

	public void initGame(final UrlFile gameXml) throws Exception {
		// set android size to custom point
		
		SizeF size = new CustomPoint.SizeF();
		size.height = 260;
		size.width = 470;
		CustomPoint.setAppScreenSize(size);

		/*
		String filePath = null;
		filePath = FilesManager.SaveTempFileFromURL(gameXml.getUrl(), gameXml
				.getFileName(), gameXml.getFileSuffix(), null, true);
				*/
		
		//this.gameInfo = new GameInfo();
		//gameInfo.ImportFromXml(filePath);
		
		RealSaxParser saxser = new RealSaxParser();
		gameInfo = saxser.parseXml(gameXml.getUrl());
		
		if (gameInfo == null)
			raiseErrorMessage("gameinfo == null");
		
		DownloadAllObjects();

		//MarkMoviesAsDontRelease();
	}

	public void playGame() {
		createMovie(gameInfo.startMovieId);
		AddGlobalElements();
	}

	private void AddGlobalElements() {
		// Adding Global Elements
		Enumeration<Integer> i = gameInfo.getElements().keys();
		for (Enumeration<Element> e = gameInfo.getElements().elements(); e
				.hasMoreElements();) {
			Element element = e.nextElement();
			int elementId = i.nextElement();
			switch (element.getElementType()) {
			case button: {
				view.AddButton(0, elementId, element.getLocation(), element
						.getColor(), true, element.getText(), true, Color.RED);
				break;
			}
			case text: {
				view.AddTextBox(0, elementId, element.getLocation(), element
						.getColor(), element.getText(), element.isFlickering());
			}

			default:
				break;
			}
		}
	}

	private void MarkMoviesAsDontRelease() {
		Dictionary<Integer, Movie> movies = gameInfo.getMovies();
		int moviesSize = movies.size();
		Enumeration<Movie> itterator = movies.elements();
		Movie tmpMovie = null;
		TreeMap<Integer, Integer> idToNumOfCalls = new TreeMap<Integer, Integer>();
		Iterator<MovieEvent> eventsItterator = null;

		for (int j = 0; j < moviesSize; j++) {
			tmpMovie = itterator.nextElement();
			/* We count only end results
			eventsItterator = tmpMovie.getEvents().iterator();
			int eventsSize = tmpMovie.getEvents().size();
			MovieEvent tmpEvent = null;
			for (int k = 0; k < eventsSize; k++) {
				tmpEvent = eventsItterator.next();
				Result[] results = tmpEvent.getResultYes();
				CountApperencesOfMovie(idToNumOfCalls, results);
				results = tmpEvent.getResultNo();
				CountApperencesOfMovie(idToNumOfCalls, results);
			}
			*/
			Result[] results = tmpMovie.getEndOfMovieResult();
			CountApperencesOfMovie(idToNumOfCalls, results);
		}

		int[] maxIdAndValue = {0, -1};
		
		itterator = movies.elements();
		for (int j = 0; j < moviesSize; j++) {
			tmpMovie = itterator.nextElement();
			int tmpId = tmpMovie.getId();
			if (idToNumOfCalls.containsKey(tmpId)) {
				int tmpVal = idToNumOfCalls.get(tmpId);
				if ( tmpVal > maxIdAndValue[0]) {
					maxIdAndValue[0] = tmpVal;
					maxIdAndValue[1] = tmpId;
				}
			}
		}
		if (maxIdAndValue[0] > dontReleaseThershold && maxIdAndValue[1] != -1)
		{
			movies.get(maxIdAndValue[1]).dontRelease = true;
		}
	}

	private void DownloadAllObjects() throws Exception {
		String value;
		for (Enumeration<Movie> iterator = gameInfo.getMovies().elements(); iterator
				.hasMoreElements();) {
			Movie movie = iterator.nextElement();

			for (MovieEvent event : movie.getSortedEvents()) {
				if (event.getType() == EventType.showMovablePicture) {
					MoveablePictureEventProperties prop = (MoveablePictureEventProperties) event
							.getProperties();

					for (int i = 0; i < prop.numOfFrames; i++) {

						String url = prop.getFrameUrl(i).getUrl();
						if (!mediaUrlToByteArray.containsKey(url)) {
							value = FilesManager.SaveTempFileFromURL(url);
							mediaUrlToByteArray.put(url, value);
						}
					}
					
				}
				if (event.getType() == EventType.click)
				{
					ClickEventProperties prop = (ClickEventProperties) event.getProperties();
					if (prop.getElementProperties().getElementType() == UiElement.pictureBox)
					{
						String url = prop.getUrl().getUrl();
						if (!mediaUrlToByteArray.containsKey(url)) {
							value = FilesManager.SaveTempFileFromURL(url);
							mediaUrlToByteArray.put(url, value);
						}
					}
				}
				
				for (Result eventResult : event.getResultYes()) {
					dowonloadReuslt(eventResult);
				}

				for (Result eventResult : event.getResultNo()) {
					dowonloadReuslt(eventResult);
				}
			}

			for (Result eventResult : movie.getEndOfMovieResult()) {
				dowonloadReuslt(eventResult);
			}
			
			if (true || movie.getIsOnline())
			{
				movie.localPath = FilesManager.SaveTempFileFromURL(movie.getUrl());
			}
		}
	}

	private void dowonloadReuslt(Result eventResult) throws Exception {
		String value;
		if (eventResult.getAction() == ResultAction.playAudio) {
			PlaySoundProperties prop = (PlaySoundProperties) eventResult
					.getProperties();
			UrlFile audioUrl = prop.getUrl();
			if (!audioUrlToSoundPoolId.containsKey(audioUrl.fileName)) {
				String audioLocalPath = null;
				int audioId = 0;
				//if (!rawResourceNameToInt.containsKey(audioUrl.fileName))
				//{
					try {
						audioLocalPath = FilesManager.SaveTempFileFromURL(audioUrl);
					} catch (IOException e) {
						view.RaiseErrorMsg(e.getMessage());
						return;
					}
					audioUrlToLocalPath.put(prop.getUrl().getUrl(), audioLocalPath);
				//}
				//else
				//{
				//	audioId = soundPool.load(view, rawResourceNameToInt.get(audioUrl.fileName),1);
				//	audioUrlToSoundPoolId.put(prop.getUrl().getUrl(), audioId);
				//}
			}
		} else if (eventResult.getAction() == ResultAction.showPicture) {
			ShowPictureResultProperties prop = (ShowPictureResultProperties) eventResult
					.getProperties();

			for (int i = 0; i < prop.numOfFrames; i++) {

				String url = prop.getFrameUrl(i).getUrl();
				if (!mediaUrlToByteArray.containsKey(url)) {
					value = FilesManager.SaveTempFileFromURL(url);
					mediaUrlToByteArray.put(url, value);
				}
			}
		}
	}

	private void CountApperencesOfMovie(
			TreeMap<Integer, Integer> idToNumOfCalls, Result[] results) {
		for (Result result : results) {
			if (result.getAction() == ResultAction.moveToMovie) {
				MoveToMovieResultProperties prop = (MoveToMovieResultProperties) result
						.getProperties();
				int nextMovieId = prop.getMovieId();
				if (idToNumOfCalls.containsKey(nextMovieId))
					idToNumOfCalls.put(nextMovieId, idToNumOfCalls
							.get(nextMovieId) + 1);
				else
					idToNumOfCalls.put(nextMovieId, 1);
			}
		}
	}

	private void createMovie(int id) {
		currentMovie = gameInfo.getMovies().get(id);
		final SurfaceView movieView = createFirstVideoView(currentMovie);
		uiHandler.post(new Runnable() {
			public void run() {
				view.addSurfaceViewAsMainView(movieView);
			}
		});
	}

	private void switchMovies(int id, final int seekTime, final boolean smoothTrans) throws Exception {
		if (movieToRelease != null) {
			movieToRelease.release();
		}

		movieToRelease = currentMovie;
		final Movie newMovie = gameInfo.getMovies().get(id);
		if (!newMovie.dontRelease || newMovie.getMView() == null) {
			uiHandler.post(new Runnable() {
				public void run() {
					SurfaceView newView = null;
					try {
						newView = createVideoView(newMovie, seekTime, smoothTrans);
						view.addSurfaceViewAsBufferingView(newView);
					} catch (Exception e) {
						raiseErrorMessage(e.getMessage());
					}
				}
			});
		} else {
			currentMovie.pause();
			
			if (this.timer != null) {
				timer.cancel();
				timer.purge();
			}

			final SurfaceView tmpOldView = currentMovie.getMView();

			uiHandler.post(new Runnable() {
				public void run() {
					view.removeView(tmpOldView);
				}
			});

			final SurfaceView tmpNewView = newMovie.getMView();

			uiHandler.post(new Runnable() {
				public void run() {
					view.makeViewMainView(tmpNewView);
				}
			});

			currentMovie = newMovie;

			currentMovie.seekTo(seekTime, this);

			view.RefreshGlobalElements();

			switichingMovies = false;
		}
	}

	private SurfaceView createFirstVideoView(Movie movie) {
		try {
			SurfaceView movieView = new SurfaceView(view);
			movieForCallback = movie;
			viewForCallback = movieView;
			movieView.getHolder().setType(
					SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
			movieView.getHolder().addCallback(new SurfaceHolder.Callback() {
				@Override
				public void surfaceCreated(SurfaceHolder holder) {
					try {
						firstSurfaceCreatedHelper();
					} catch (Exception e) {
						view.RaiseErrorMsg(e.getMessage());
						return;
					}
				}

				@Override
				public void surfaceChanged(SurfaceHolder holder, int format,
						int width, int height) {
				}

				@Override
				public void surfaceDestroyed(SurfaceHolder holder) {
				}
			});
			return movieView;
		} catch (Exception e) {
			view.RaiseErrorMsg(e.getMessage());
		}
		return null;
	}

	private void firstSurfaceCreatedHelper() throws Exception {

		view.stopProgressBar();
		
		movieForCallback.prepare(viewForCallback);
		
		movieForCallback.setOnCompletionListener(eventManager);

		movieForCallback = null;
		viewForCallback = null;

		if (this.timer != null) {
			timer.cancel();
			timer.purge();
		}

		currentMovie.play();
		
		this.timer = new Timer();

		Log.w("InTouchTV", "");
		Log.w("InTouchTV", currentMovie.url.fileName + " Events:");
		for (MovieEvent event : currentMovie.getSortedEvents()) {
			Log.w("InTouchTV", Integer.toString(event.id));
			startTask(event, 0);
			endTask(event, 0);
		}

		view.RefreshGlobalElements();

		switichingMovies = false;
	}

	public void endTask(MovieEvent event, int jumpTime) {
		if (event.getEndTime() > jumpTime && event.getEndTime() < 790000)
			timer.schedule(new EndEventTimerTask(event, view, currentMovie,
					this), (event.getEndTime() - jumpTime));
	}

	public void startTask(final MovieEvent event, int jumpTime) {
		if (event.getEndTime() > jumpTime) {
			timer.schedule(new StartEventTimerTask(event, view, currentMovie,
					this), (Math.max(0, event.getStartTime() - jumpTime)));
		} else {
			Log.d("BUG", "Missed a button");
		}
	}

	private SurfaceView createVideoView(Movie movie, final int seekTime, final boolean smoothTrans) {
		SurfaceView movieView = new SurfaceView(view);
		movieForCallback = movie;
		viewForCallback = movieView;
		movieView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		movieView.getHolder().addCallback(new SurfaceHolder.Callback() {
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				try {
					surfaceCreatedHelper(seekTime, smoothTrans);
				} catch (Exception e) {
					view.RaiseErrorMsg(e.getMessage());
					return;
				}
			}

			@Override
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
			}

			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
			}
		});
		return movieView;
	}

	private void surfaceCreatedHelper(int seekTime, boolean smoothTrans) throws Exception {
		if (smoothTrans)
			prepareWithSmoothTransition(seekTime);
		else
			prepareWithFadeOut(seekTime);
	}
	
	private void prepareWithSmoothTransition(int seekTime) throws Exception
	{
		if (this.timer != null) {
			timer.cancel();
			timer.purge();
		}
		
		movieForCallback.prepare(viewForCallback);
		
		movieForCallback.setOnCompletionListener(eventManager);

		currentMovie.pause();

		if (!currentMovie.dontRelease) {
			view.removeView(currentMovie.getMView());
		} else {
			view.moveViewToAllwaysKeepLocation(currentMovie.getMView());
		}

		view.makeViewMainView(viewForCallback);

		currentMovie = movieForCallback;

		currentMovie.seekTo(seekTime, this);
	}
	
	private void prepareWithFadeOut(int seekTime) throws Exception
	{
		currentMovie.pause();
		
		if (this.timer != null) {
			timer.cancel();
			timer.purge();
		}
		
		if (!currentMovie.dontRelease) {
			view.removeView(currentMovie.getMView());
			currentMovie.release();
			System.gc();
		} else {
			view.moveViewToAllwaysKeepLocation(currentMovie.getMView());
			currentMovie.seekToAndDontPlay(0);
		}

		movieForCallback.prepare(viewForCallback);
		
		view.makeViewMainView(viewForCallback);

		currentMovie = movieForCallback;
		
		currentMovie.setOnCompletionListener(eventManager);

		currentMovie.seekTo(seekTime, this);
	}
	
	public void playingCallback(Movie movie, int timerSeekTime)
	{	
		timer = new Timer();
		HashSet<MovieEvent> seenEvents = new HashSet<MovieEvent>(); 
		Log.w("InTouchTV", "");
		Log.w("InTouchTV", movie.url.fileName + " Events:");
		for (MovieEvent event : movie.getSortedEvents()) {
			if (!seenEvents.contains(event))
			{
				Log.w("InTouchTV", Integer.toString(event.id));
				startTask(event, timerSeekTime);
				endTask(event, timerSeekTime);
				seenEvents.add(event);
			}
		}
		
		movieForCallback = null;
		viewForCallback = null;

		view.RefreshGlobalElements();

		switichingMovies = false;
	}

	public void release() {
		if (currentMovie != null)
			currentMovie.forceRelease();
		if (movieForCallback != null)
			movieForCallback.forceRelease();
		if (movieToRelease != null)
			movieToRelease.forceRelease();
		if (soundPool != null)
			soundPool.release();
	}

	public void removeEventElement(MovieEvent event) {
		eventManager.removeListedEvent(event);
		view.removeElement(event.getId(), this.currentMovie.getId());
	}

	public void performResult(int id, Result result) throws Exception {
		// Don't do anything if we are in the middle of a movie swtich
		if (switichingMovies)
			return;
		
		//if the result checks a flag first and its false
		if ((result.getCheckFlag() != null) && !(getFlags().get(result.getCheckFlag())))
			return;

		switch (result.getAction()) {
		case changeGlobalElementText: {
			ChangeGlobleElementTextResultProprties prop = (ChangeGlobleElementTextResultProprties) result
					.getProperties();
			view.changeElementText(0, prop.getElementId(), prop.getText());
			break;
		}
		case killEvent:
		{
			KillEventResultProperties prop = (KillEventResultProperties) result.getProperties();
			eventManager.removeListedEvent(prop.getEventId());
			break;
		}
		case startActivity:
		{
			StartActivityProperties prop = (StartActivityProperties) result.getProperties();
			String activityName = prop.getActivityName();
			Intent newActivityIntent = view.getPackageManager().getLaunchIntentForPackage(activityName);
			//PackageInfo pi = view.getPackageManager().getPackageInfo(activityName, PackageManager.GET_SERVICES | PackageManager.GET_ACTIVITIES);
			if (activityName == "com.bambuser.broadcaster")
				newActivityIntent.putExtra("autostart", true);
			else
				newActivityIntent.putExtra("autostart", true);
			view.startActivity(newActivityIntent);
			break;
		}
		case setFlag:
		{
			SetFlagResultProperties prop = (SetFlagResultProperties)result.getProperties();
			
			if (getFlags().get(prop.getFlagName())!= null)
			{
					switch (prop.getFlagVlaue()) {
					case setTrue:
					{
						getFlags().put(prop.getFlagName(), true);
						break;
					}
					case setFalse:
					{
						getFlags().put(prop.getFlagName(), false);
						break;
					}
					case flip:
					{
						getFlags().put(prop.getFlagName(), 
								!getFlags().get(prop.getFlagName()));
						break;
					}
						
					}
			}
			break;
						
		}
		case moveToMovie: {
			// get the properties of the result
			MoveToMovieResultProperties prop = (MoveToMovieResultProperties) result
					.getProperties();

			// get the seek time of the new movie
			int seekTime = 0;
			seekTime = prop.getTime();

			view.removeMovieElements(currentMovie.getId());
			for (MovieEvent event : currentMovie.getSortedEvents()) {
				event.setIsResultYes(false);
				eventManager.removeListedEvent(event);
			}
			
			
			if (currentMovie.getId() != prop.getMovieId()) {
				switichingMovies = true;
				switchMovies(prop.getMovieId(), seekTime, prop.isSmoothTrans());
			} else {
				if (this.timer != null) {
					timer.cancel();
					timer.purge();
				}
				currentMovie.seekTo(seekTime, this);
			}

			break;
		}

		case killApplication: {
			view.finish();
		}

		case playAudio: {
			PlaySoundProperties prop = (PlaySoundProperties) result
					.getProperties();
			playAudio(prop.getUrl(), prop.isMoviePaused(), prop.loop);
			break;
		}
		case initFlags:{
			Enumeration<String> keys = gameInfo.flagsInitialValue.keys();
			while (keys.hasMoreElements()) {
				String key = (String) keys.nextElement();
				gameInfo.flags.remove(key);
				gameInfo.flags.put(key, 
						gameInfo.flagsInitialValue.get(key));
			}
			break;
		}
		case stopSound:{
			StopSoundResultProperties prop = (StopSoundResultProperties) result
			.getProperties();
			stopAudioFromMediaPlayer(prop.getUrl().getUrl());
			break;
		}
		case hidePicture: {
			try{
				view.removeElement(id, currentMovie.getId());
			}catch (Exception e){}
		}
		case showPicture: {
			final ShowPictureResultProperties prop = (ShowPictureResultProperties) result
					.getProperties();

			if (prop.isMoviePaused())
				currentMovie.pause();

			Bitmap[] frames = new Bitmap[prop.numOfFrames];
			for (int i = 0; i < frames.length; i++) {
				BitmapFactory.Options options=new BitmapFactory.Options();
				options.inSampleSize = 1;
				try{
					frames[i] = BitmapFactory.decodeFile(mediaUrlToByteArray.get(prop.getUrl().getUrl()), options);
					currentMovie.frames.add(frames[i]);
				}
				catch (Exception e)
				{
					raiseErrorMessage(e.getMessage());
				}
			}

			// check if this is an animated picture
			if (prop.numOfFrames > 1) {

				view.AddAnimatedGif(currentMovie.getId(), id, prop
						.getLocation(), frames);
			} else {
				view.AddPictureBox(currentMovie.getId(), id,
						prop.getLocation(), frames[0],prop.isFlickering(),
						false);
			}

			// set timer for the duration of the picture
			this.timer.schedule(new ParamTimerTask<Integer, Integer>(id,currentMovie
					.getId()) {
				@Override
				public void run() {
					view.removeElement(this.param1, this.param2);
					if (prop.isMoviePaused()) {
						try {
							currentMovie.play();
						} catch (Exception e) {
							view.RaiseErrorMsg(e.getMessage());
							return;
						}
					}
				}
			}, prop.getDuration());
		}
			break;
		}
	}

	public void eventOccurred(int eventId) throws Exception {

		MovieEvent currentEvent = getCurrentMovieEvent(eventId);

		currentEvent.setIsResultYes(true);
		
		if (currentEvent.getResultYes().length > 0)
		{
			eventManager.removeListedEvent(currentEvent);
			view.removeElement(eventId, currentMovie.getId());
		}

		for (Result result : currentEvent.getResultYes()) {
			performResult(currentEvent.getId(), result);
		}
	}

	public void playAudio(UrlFile url, final boolean pauseMovie, boolean loop)
			throws Exception {
		if (pauseMovie)
		{
			currentMovie.pause();
			if (audioUrlToSoundPoolId.containsKey(url.getUrl()))
				playAudioFromSoundPool(url.getUrl());
			else
				playAudioFromMediaPlayer(url.getUrl(), false);					
			currentMovie.start();
		}
		else
			if (audioUrlToSoundPoolId.containsKey(url.getUrl()))
				playAudioFromSoundPool(url.getUrl());
			else
				playAudioFromMediaPlayer(url.getUrl(), loop);	
	}

	public void playAudioFromSoundPool(String url) {
		AudioManager audioMgr = (AudioManager) view.getApplicationContext()
		.getSystemService(Context.AUDIO_SERVICE);
		int streamVolume = audioMgr.getStreamVolume(AudioManager.STREAM_MUSIC);
		try{
			soundPool.play(audioUrlToSoundPoolId.get(url), streamVolume,
				streamVolume, 1, 0, 1f);
		}catch(Exception e){
			raiseErrorMessage(e.getMessage());
		}
	}
	
	public void stopSudioFromSoundPool(String url){
		try{
			soundPool.stop(audioUrlToSoundPoolId.get(url));
		}catch(Exception e){
			raiseErrorMessage(e.getMessage());
		}
	}
	
	

	public void stopAudioFromMediaPlayer(String url)
	{
		try{
			MediaPlayer player = audioPlayers.get(url);
			player.stop();
			player.release();
			audioPlayers.remove(url);
		}
		catch(Exception e)
		{
			Log.d("NabDemo", "stopAudio "+e.getLocalizedMessage());
		}
	}

	public void playAudioFromMediaPlayer(String url, boolean loop) throws Exception {
		//currentMovie.pause();
		MediaPlayer audioPlayer = new MediaPlayer();
		audioPlayer.setDataSource(audioUrlToLocalPath.get(url));
		audioPlayer.prepare();
		audioPlayer.setLooping(loop);
		audioPlayers.put(url, audioPlayer);
		audioPlayer
				.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
					@Override
					public void onCompletion(MediaPlayer mp) {
						try {
							Thread.sleep(100);// An hack - sometime the movie
							// didn't start
							//currentMovie.start();
						} catch (Exception e) {
						}
						finally{
							mp.release();
						}
					}
				});
		audioPlayer.start();
	}

	public void movieEnded() throws Exception {
		for (Result result : currentMovie.getEndOfMovieResult()) {
			performResult(0, result);
		}
	}

	public Rect getGlobaleElementLoction(int id) {
		return this.gameInfo.getElements().get(id).getLocation();
	}

	public int getGlobaleElementColor(int id) {
		return this.gameInfo.getElements().get(id).getColor();
	}

	public MovieEvent getCurrentMovieEvent(int eventId) {
		try {
			return currentMovie.getEvent(eventId);
		} catch (Exception e) {
			view.RaiseErrorMsg(e.getMessage());
			return null;
		}
	}

	public void raiseErrorMessage(String str) {
		Log.d("NabDemoError", str == null ? "error....." : str);
		view.RaiseErrorMsg(str);
	}

	public Dictionary<String, Boolean> getFlags() {
		return gameInfo.getFlags();
	}
	
}
